package org.lqq.remoteClient;

import org.lqq.entity.ServerAddress;
import org.lqq.loadbalance.LoadBalancer;
import org.lqq.serverRegisterAndFinder.serverFinder.ServerFinder;

import java.util.Collection;

/**
 * Created by 李清泉 on 2017/10/26.
 *
 * @remark 远程对象抽象实现
 */
public abstract class AbstractRemoteClient implements RemoteClient {

    protected ServerFinder serverFinder;

    protected LoadBalancer loadBalancer;

    public AbstractRemoteClient(ServerFinder serverFinder, LoadBalancer loadBalancer) {
        this.serverFinder = serverFinder;
        this.loadBalancer = loadBalancer;
    }

    protected String getReqUrl(String serverName) {
        Collection<ServerAddress> list = serverFinder.discoverServerAddress(serverName);
        ServerAddress serverAddress = loadBalancer.choose(list);
        return serverAddress != null ? serverAddress.getReqBaseUrl() : null;
    }

    /**
     * 模板模式实现主方法
     *
     * @param clazz
     * @return
     */
    @Override
    public <T> T createRemoteObject(Class<T> clazz) {
        if (clazz == null) {
            throw new RuntimeException("Remote class can not be null!");
        }
        if (!clazz.isInterface()) {
            throw new RuntimeException("Remote class must a Interface!");
        }
        if (!clazz.isAnnotationPresent(RemoteServerName.class)) {
            throw new RuntimeException("Remote class must have annotation class: RemoteServerName!");
        }

        RemoteServerName remoteServerName = clazz.getAnnotation(RemoteServerName.class);
        String serverName = remoteServerName.value();
        if (serverName == null || serverName.trim().length() == 0) {
            throw new RuntimeException("Remote class must have serverName!");
        }
        String url = getReqUrl(serverName);
        if (url == null || url.trim().length() == 0) {
            throw new RuntimeException("Remote Server has bean shut down!");
        }
        return doGetRemoteObject(clazz, url);
    }

    /**
     * 获取远程对象
     *
     * @param clazz
     * @param url
     * @return
     */
    protected abstract <T> T doGetRemoteObject(Class<T> clazz, String url);
}
